package daemon

import (
	"context"
	"os"
	"os/signal"
	"syscall"
	"time"

	_cfg "github.com/romapres2010/goapp/pkg/app/config"
	_err "github.com/romapres2010/goapp/pkg/common/error"
	_httplog "github.com/romapres2010/goapp/pkg/common/httplog"
	_httpserver "github.com/romapres2010/goapp/pkg/common/httpserver"
	_http "github.com/romapres2010/goapp/pkg/common/httpservice"
	_log "github.com/romapres2010/goapp/pkg/common/logger"
	_wpservice "github.com/romapres2010/goapp/pkg/common/workerpoolservice"

	httphandler "github.com/romapres2010/goapp/pkg/app/httphandler"
)

// Daemon represent top level daemon
type Daemon struct {
	ctx    context.Context    // 根上下文
	cancel context.CancelFunc // 关闭根上下文的函数
	cfg    *_cfg.Config       // 守护进程的配置

	// 守护进程的服务
	httpServer      *_httpserver.Server // HTTP服务器
	httpServerErrCh chan error          // HTTP服务器的错误通道

	httpLogger      *_httplog.Logger // HTTP流量日志服务
	httpLoggerErrCh chan error       // HTTP日志服务的错误通道

	httpService      *_http.Service // HTTP请求服务
	httpServiceErrCh chan error     // HTTP服务的错误通道

	httpHandler      *httphandler.Service // HTTP请求处理服务
	httpHandlerErrCh chan error           // HTTP处理服务的错误通道

	wpService      *_wpservice.Service // 工作池服务
	wpServiceErrCh chan error          // 工作池服务的错误通道
}

// New create Daemon
func New(ctx context.Context, cfg *_cfg.Config) (*Daemon, error) {
	var err error

	_log.Info("Create new daemon")

	{ // 输入检查
		if cfg == nil {
			return nil, _err.NewTyped(_err.ERR_INCORRECT_CALL_ERROR, _err.ERR_UNDEFINED_ID, "if cfg == nil {}").PrintfError()
		}
	} // 输入检查

	// 创建一个新的守护进程
	daemon := &Daemon{
		cfg:              cfg,
		httpServerErrCh:  make(chan error, 1),
		httpServiceErrCh: make(chan error, 1),
		httpHandlerErrCh: make(chan error, 1),
		httpLoggerErrCh:  make(chan error, 1),
		wpServiceErrCh:   make(chan error, 1),
	}

	// 创建带有取消功能的根上下文
	if ctx == nil {
		daemon.ctx, daemon.cancel = context.WithCancel(context.Background())
	} else {
		daemon.ctx, daemon.cancel = context.WithCancel(ctx)
	}

	// 创建处理器服务
	if daemon.wpService, err = _wpservice.New(daemon.ctx, "WorkerPool - background", daemon.wpServiceErrCh, &daemon.cfg.WorkerPoolServiceCfg); err != nil {
		return nil, err
	}

	// 创建用于记录HTTP日志的处理程序
	if daemon.httpLogger, err = _httplog.New(daemon.ctx, &daemon.cfg.HttpLoggerCfg); err != nil {
		return nil, err
	}

	// HTTP服务和HTTP日志记录器
	if daemon.httpService, daemon.httpLogger, err = _http.New(daemon.ctx, &daemon.cfg.HttpServiceCfg, daemon.httpLogger); err != nil {
		return nil, err
	}

	// 创建HTTP处理器
	if daemon.httpHandler, err = httphandler.New(daemon.ctx, &daemon.cfg.HttpHandlerCfg, daemon.wpService, daemon.httpService); err != nil {
		return nil, err
	}

	// 设置HTTP处理器
	if err = daemon.httpService.SetHttpHandler(daemon.ctx, daemon.httpHandler); err != nil {
		return nil, err
	}

	// 创建HTTP服务器
	if daemon.httpServer, err = _httpserver.New(daemon.ctx, daemon.httpServerErrCh, &daemon.cfg.HttpServerCfg, daemon.httpService); err != nil {
		return nil, err
	}

	_log.Info("New daemon was created")

	return daemon, nil
}

// Run daemon and wait for system signal or error in error channel
func (d *Daemon) Run() error {
	_log.Info("Starting daemon")

	// 启动工作池服务处理器 - 任何恐慌（panic）都应该在内部处理
	go func() { d.wpServiceErrCh <- d.wpService.Run() }()

	// 在后台启动HTTP服务器，错误返回到错误通道 - 任何恐慌（panic）都应该在内部处理
	go func() { d.httpServerErrCh <- d.httpServer.Run() }()

	_log.Info("Daemon was running. For exit <CTRL-c>")

	// 订阅系统信号
	signalCh := make(chan os.Signal, 1) // 系统信号的通道
	signal.Notify(signalCh, syscall.SIGINT, syscall.SIGTERM)

	// 等待中断或错误通道中的返回
	for {
		var err error
		select {
		case s := <-signalCh: // 等待系统信号
			_log.Info("Exiting, got signal", s)
			d.Shutdown(false, d.cfg.ShutdownTimeout) // 停止守护进程
			return nil
		case err = <-d.httpServerErrCh: // 从HTTP服务器的错误通道返回
			_log.Info("Got error from HTTP")
		case err = <-d.wpServiceErrCh: // 从工作池的错误通道返回
			_log.Info("Got error from worker pool")
		}

		// 如果服务返回了一个空错误 - 我们忽略它
		if err != nil {
			_log.Error(err.Error())                 // 记录错误
			d.Shutdown(true, d.cfg.ShutdownTimeout) // 停止守护进程
			return err
		} else {
			_log.Info("Got empty error - ignore it")
		}
	}
}

// Shutdown daemon
func (d *Daemon) Shutdown(hardShutdown bool, shutdownTimeout time.Duration) {
	_log.Info("Shutting down daemon")

	// 关闭根上下文
	defer d.cancel()

	// 停止工作池处理器 - 中断当前任务的处理
	if err := d.wpService.Shutdown(hardShutdown, shutdownTimeout); err != nil {
		_log.ErrorAsInfo(err) // дополнительно логируем результат остановки
	}

	// 停止服务服务
	if err := d.httpService.Shutdown(); err != nil {
		_log.ErrorAsInfo(err) // дополнительно логируем результат остановки
	}

	// 停止HTTP服务器，等待活动连接结束
	if err := d.httpServer.Shutdown(); err != nil {
		_log.ErrorAsInfo(err) // дополнительно логируем результат остановки
	}

	_log.Info("Daemon was shutdown")

	// 关闭日志记录器，以便正确关闭日志文件
	if err := d.httpLogger.Shutdown(); err != nil {
		_log.ErrorAsInfo(err) // дополнительно логируем результат остановки
	}
}
